#include "head.h"

static int recvn(int sockfd, void *buf, int length);

int workCmd(int netFd){
    //初始化名字
    printf("Plz enter user name:");
    char name[50];
    scanf("%s",name);

    train_t train;
    train.length = strlen(name);
    memcpy(train.data,name,train.length);
    /* printf("%d ,%s\n",train.length,train.data); */
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);
    
    client_t *client = (client_t*)calloc(1,sizeof(client_t));
    client->fd = netFd;
    memcpy(client->userName,train.data,train.length);

    //初始地址什么都没
    strcpy(client->pwd,"");
    while(1){
        printf("%s$ \n",client->pwd);
        fflush(stdin);
        fflush(stdout);

        //获取命令
        char temp[1024] = {0};
        read(STDIN_FILENO,temp,sizeof(temp));
        temp[strlen(temp)-1] = 0;

        //分离命令
        char cmd [1024] = {0};
        strcpy(cmd,temp);
        char cmdfix[1024] = {0};//存放处理好的数据
        char *p = strtok(temp," ");
        strcpy(cmd,p);//cmd存放系统调用命令
        int first = 1;
        while(p != NULL){
            if(first){
                first = 0;
            }else{
                strcat(cmdfix,p);
            }
            p = strtok(NULL," ");
        }

        if(strncmp("cd",cmd,2)==0){
            //todo  将处理好的字符串放data中
            TLVtrain_t tlv;
            tlv.type = CD ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);
            //发送目标路径

            //接收新路径
        }
        else if(strcmp("ls",cmd)==0){
            TLVtrain_t tlv;
            tlv.type = LS ;
            strcpy(tlv.data,"Y");
            tlv.length = strlen(train.data);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);

            char dirName [1024] = {0};
            int dirLength = 0;
            while(1){
                bzero(dirName,sizeof(dirName));
                recvn(netFd,&dirLength,sizeof(int));
                recvn(netFd,dirName,dirLength);
                if(dirLength == 0){
                    break;
                }
                printf("%s ",dirName);
            }
            printf("\n");
        }
        else if(strcmp("ll",cmd)==0){
            TLVtrain_t tlv;
            tlv.type = LL ;
            tlv.length = 1;
            strcpy(tlv.data,"Y");
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);

            char dirInfo [1024] = {0};
            int infoLength = 0;
            while(1){
                bzero(dirInfo,sizeof(dirInfo));
                recvn(netFd,&infoLength,sizeof(int));
                recvn(netFd,dirInfo,infoLength);
                if(infoLength == 0){
                    break;
                }
                printf("%s\n",dirInfo);
            }
            printf("\n");
        }
        else if (strcmp("pwd",cmd)==0){
            printf("%s\n",client->pwd);
        }
        else if(strncmp("puts",cmd,4)==0){
            TLVtrain_t tlv;
            tlv.type = PUTS ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);

            sendFile(netFd,cmdfix);
        }
        else if(strncmp("gets",cmd,4)==0){
            TLVtrain_t tlv;
            tlv.type = GETS ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);

            recvFile(netFd);
        }
        else if(strncmp("remove",cmd,6)==0){
            TLVtrain_t tlv;
            tlv.type = REMOVE ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);
            //回执
            bzero(&train,sizeof(train));
            recvn(netFd,&train.length,sizeof(train.length));
            recvn(netFd,train.data,train.length);
            if(strcmp(train.data,"N")){
                printf("File deleted successfully.\n");
            }else{
                printf("File deleted error.\n");                                                                                    
            }
        }
        else if(strncmp("mkdir",cmd,5)==0){
            TLVtrain_t tlv;
            tlv.type = MKDIR ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);
            //回执
            bzero(&train,sizeof(train));
            recvn(netFd,&train.length,sizeof(train.length));
            recvn(netFd,train.data,train.length);
            if(strcmp(train.data,"N")){
                printf("Dir create successfully.\n");
            }else{
                printf("Dir create error.\n");                                                                                    
            }
        }
        else if(strncmp("rmdir",cmd,2)==0){
            TLVtrain_t tlv;
            tlv.type = RMDIR ;
            strcpy(tlv.data,cmdfix);
            tlv.length = strlen(cmdfix);
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);
            //回执
            bzero(&train,sizeof(train));
            recvn(netFd,&train.length,sizeof(train.length));
            recvn(netFd,train.data,train.length);
            if(strcmp(train.data,"N")){
                printf("Dir deleted successfully.\n");
            }else{
                printf("Dir deleted error.\n");                                                                                    
            }
        }
        else if(strcmp("quit",cmd)==0){
            TLVtrain_t tlv;
            tlv.type = QUIT ;
            tlv.length = 1;
            strcpy(tlv.data,"N");
            send(netFd,&tlv.type,sizeof(tlv.type),MSG_NOSIGNAL);
            send(netFd,&tlv.length,sizeof(tlv.length),MSG_NOSIGNAL);
            send(netFd,tlv.data,tlv.length,MSG_NOSIGNAL);
            printf("Bye-bye!\n");
            break;
        }
        else{
            //命令输入错误
            printf("Plz input right cmd or 'quit'.\n");
        }
    }
    return 0;
}

// v1.0小文件 粘包
//int recvFile(int netfd){
//    char filename[4096] = {0};
//    recv(netfd,filename,sizeof(filename),0);
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    char buf[1000] = {0};
//    ssize_t sret = recv(netfd,buf,sizeof(buf),0);
//    write(fd,buf,sret);
//    close(fd);
//    return 0;
//}
// v2.0 小文件小火车协议
//int recvFile(int netfd){
//    train_t train;
//    char filename[4096] = {0};
//    recv(netfd,&train.length,sizeof(train.length),0);//收火车头
//    recv(netfd,train.data,train.length,0);//收车厢
//    memcpy(filename,train.data,train.length);
//
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    recv(netfd,&train.length,sizeof(train.length),0);//收火车头
//    recv(netfd,train.data,train.length,0);//收车厢
//    write(fd,train.data,train.length);
//
//    close(fd);
//    return 0;
//}
//
//v3.0 大文件循环
//int recvFile(int netfd){
//    train_t train;
//    char filename[4096] = {0};
//    recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);//收火车头
//    recv(netfd,train.data,train.length,MSG_WAITALL);//收车厢
//    memcpy(filename,train.data,train.length);
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    while(1){
//        recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);//收火车头
//        if(train.length != 1000){
//            printf("train.length = %d\n", train.length);
//        }
//        if(train.length == 0){
//            break;
//        }
//        recv(netfd,train.data,train.length,MSG_WAITALL);//收车厢
//        write(fd,train.data,train.length);
//    }
//    close(fd);
//    return 0;
//}
// v3.1
static int recvn(int sockfd, void *buf, int length){
    int total = 0;
    char *p = (char *)buf;
    while(total < length){
        ssize_t sret = recv(sockfd,p+total,length-total,0);
        total += sret;
    }
    return total;
}

//recvn封装版本，强制recv完
/* int recv_file(int netfd){ */
/*     train_t train; */
/*     char filename[4096] = {0}; */
/*     recvn(netfd,&train.size,sizeof(train.size));//收火车头 */
/*     recvn(netfd,train.buf,train.size);//收车厢 */
/*     memcpy(filename,train.buf,train.size); */
/*     int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666); */
/*     while(1){ */
/*         recvn(netfd,&train.size,sizeof(train.size));//收火车头 */
/*         if(train.size != 1000){ */
/*             printf("train.size = %d\n", train.size); */
/*         } */
/*         if(train.size == 0){ */
/*             break; */
/*         } */
/*         recvn(netfd,train.buf,train.size);//收车厢 */
/*         write(fd,train.buf,train.size); */
/*     } */
/*     close(fd); */
/*     return 0; */
/* } */

//recvn封装版本，强制recv完，进度条
//小文件秒传，大文件慢慢传
int recvFile(int netfd){
    train_t train;
    char filename[4096] = {0};
    recvn(netfd,&train.length,sizeof(train.length));//收火车头
    recvn(netfd,train.data,train.length);//收车厢
    memcpy(filename,train.data,train.length);
    printf("%s\n",filename);

    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fd,-1,"open");

    off_t filesize = 0;
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    memcpy(&filesize,train.data,train.length);

    printf("Filesize = %ld\n",filesize);
    if(filesize < 4096){
        printf("Tiny file.\n");
        ftruncate(fd,filesize);
        char *p = (char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        recvn(netfd,p,filesize);
        munmap(p,filesize);
    }
    else{
        printf("Hurge file~\n");
        off_t currsize = 0;
        while(1){
            recvn(netfd,&train.length,sizeof(train.length));//收火车头
            if(train.length == 0){
                break;
            }
            currsize += train.length;
            printf("%5.2lf%%\r",100.0*currsize/filesize);
            fflush(stdout);

            sleep(1);
            recvn(netfd,train.data,train.length);//收车厢
            write(fd,train.data,train.length);
        }
    }
    printf("100.00%%\n");
    close(fd);
    return 0;
}
int sendFile(int netFd,char *file){
    train_t train;
    train.length = strlen(file);
    memcpy(train.data,file,train.length);
    printf("%d ,%s\n",train.length,train.data);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    int fd = open(file,O_RDWR);
    struct stat statbuf;
    fstat(fd,&statbuf);
    off_t filesize = statbuf.st_size;
    train.length = sizeof(filesize);
    memcpy(train.data,&filesize,train.length);
    send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netFd,train.data,train.length,MSG_NOSIGNAL);

    printf("Filesize = %ld\n",filesize);
    //小文件秒传，大文件小火车传
    if(filesize < 4096){
        printf("Tiny file.\n");
        char *p = (char *)mmap(NULL,filesize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        send(netFd,p,filesize,MSG_NOSIGNAL);
        munmap(p,filesize);
    }
    else{
        printf("Hurge file~\n");
        while(1){
            bzero(train.data,sizeof(train.data));
            ssize_t ret = read(fd,train.data,sizeof(train.data));
            train.length = ret;
            send(netFd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
            send(netFd,train.data,train.length,MSG_NOSIGNAL);
            if(ret == 0){
                break;
            }
        }
    }
    close(fd);
    return 0;
}

